using Microsoft.EntityFrameworkCore;
using Net8.Identity.Server.Extensions;
using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants;

namespace Net8.Identity.Server.Services
{
    public interface IClientsSeeder
    {
        Task EnsureMigrationAsync();
    }
    
    /// <summary>
    /// 注入种子数据
    /// 把一些种子数据在项目运行时提前注入到数据库中，这一步大家按需执行即可。
    /// </summary>

    public class ClientsSeeder : IClientsSeeder
    {
        private readonly IServiceProvider _serviceProvider;

        public ClientsSeeder(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
        public async Task EnsureMigrationAsync()
        {
            using var scope = _serviceProvider.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            await context.Database.MigrateAsync();

            await RegisterApplicationsAsync(scope.ServiceProvider);
            await RegisterScopesAsync(scope.ServiceProvider);

            await RegisterClientsAsync(scope.ServiceProvider);
            await RegisterInitUsersAsync(scope.ServiceProvider);
            await RegisterCorsSettingsAsync(scope.ServiceProvider);
        }

        /// <summary>
        /// 注册外部Oidc应用程序
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        private static async Task RegisterApplicationsAsync(IServiceProvider provider)
        {
            var manager = provider.GetRequiredService<IOpenIddictApplicationManager>();

            if (await manager.FindByClientIdAsync("oidc-debugger") is null)
            {
                var descriptor = new OpenIddictApplicationDescriptor
                {
                    ClientId = "oidc-debugger",
                    ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654",
                    ConsentType = ConsentTypes.Explicit,
                    DisplayName = "Postman client application",
                    // 获取与应用程序关联的重定向URI。
                    RedirectUris = { new Uri("https://oidcdebugger.com/debug") },
                    // 获取与应用程序关联的注销后重定向URI
                    PostLogoutRedirectUris = { new Uri("https://oauth.pstmn.io/v1/callback") },
                    // 获取与应用程序关联的权限
                    Permissions = {
                        Permissions.Endpoints.Authorization,
                        Permissions.Endpoints.Token,
                        Permissions.GrantTypes.AuthorizationCode,
                        Permissions.ResponseTypes.Code,
                        Permissions.Scopes.Email,
                        Permissions.Scopes.Profile,
                        Permissions.Scopes.Roles,
                        Permissions.Endpoints.EndSession,
                        $"{Permissions.Prefixes.Scope}api1"
                     },
                    //Requirements =
                    //    {
                    //        Requirements.Features.ProofKeyForCodeExchange
                    //    }
                };

                await manager.CreateAsync(descriptor);
            }
        }

        /// <summary>
        /// 注册作用域
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        private static async Task RegisterScopesAsync(IServiceProvider provider)
        {
            var manager = provider.GetRequiredService<IOpenIddictScopeManager>();

            if (await manager.FindByNameAsync("api1") == null)
            {
                var descriptor = new OpenIddictScopeDescriptor
                {
                    DisplayName = "Api scope",
                    Name = "api1",
                    Resources ={
                           "resource_server_1"
                        }
                };

                await manager.CreateAsync(descriptor);
            }
        }

        /// <summary>
        /// 注册客户端应用程序
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        private static async Task RegisterClientsAsync(IServiceProvider provider)
        {
            var manager = provider.GetRequiredService<IOpenIddictApplicationManager>();
            if (await manager.FindByClientIdAsync("web-client") is null)
            {
                var descriptor = new OpenIddictApplicationDescriptor
                {
                    ClientId = "web-client",
                    ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654",
                    ConsentType = ConsentTypes.Explicit,
                    DisplayName = "Postman客户端应用程序",
                    // 获取与应用程序关联的重定向URI
                    RedirectUris = { new Uri("https://localhost:7002/swagger/oauth2-redirect.html") },
                    // 获取与应用程序关联的注销后重定向URI
                    PostLogoutRedirectUris = { new Uri("https://localhost:7002/resources") },
                    // 获取与应用程序关联的权限
                    Permissions = {
                        Permissions.Endpoints.Authorization,
                        Permissions.Endpoints.Token,
                        Permissions.GrantTypes.AuthorizationCode,
                        Permissions.ResponseTypes.Code,
                        Permissions.Scopes.Email,
                        Permissions.Scopes.Profile,
                        Permissions.Scopes.Roles,
                        Permissions.Endpoints.EndSession,
                        $"{Permissions.Prefixes.Scope}api1"
                    },
                    // 获取与应用程序关联的要求
                    Requirements = { Requirements.Features.ProofKeyForCodeExchange }
                };
                await manager.CreateAsync(descriptor);
            }

            if (await manager.FindByClientIdAsync("mvc") is null)
            {
                var descriptor = new OpenIddictApplicationDescriptor
                {
                    ClientId = "mvc",
                    ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654",
                    ConsentType = ConsentTypes.Explicit,
                    DisplayName = "mvc客户端应用程序",
                    // 获取与应用程序关联的重定向URI
                    RedirectUris = { new Uri("https://localhost:7164/callback/login/local") },
                    // 获取与应用程序关联的注销后重定向URI
                    PostLogoutRedirectUris = { new Uri("https://localhost:7164/callback/logout/local") },
                    // 获取与应用程序关联的权限
                    Permissions = {
                        Permissions.Endpoints.Authorization,
                        Permissions.Endpoints.Token,
                        Permissions.GrantTypes.AuthorizationCode,
                        Permissions.ResponseTypes.Code,
                        Permissions.Scopes.Email,
                        Permissions.Scopes.Profile,
                        Permissions.Scopes.Roles,
                        Permissions.Endpoints.EndSession,
                        //$"{Permissions.Prefixes.Scope}api1"
                    },
                    Requirements = { Requirements.Features.ProofKeyForCodeExchange }
                };
                await manager.CreateAsync(descriptor);
            }
        }

        /// <summary>
        /// 注册初始用户
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        private static async Task RegisterInitUsersAsync(IServiceProvider provider)
        {
            var context = provider.GetRequiredService<ApplicationDbContext>();
            if (!context.Users.Any())
            {
                await context.Users.AddAsync(new Models.User()
                {
                    UserName = "test1",
                    Password = PasswordHasher.HashPassword("123456"),
                    Email = "wtlemon@126.com",
                    Mobile = "110",
                    Remark = "初始化测试账号"
                });
                await context.Users.AddAsync(new Models.User()
                {
                    UserName = "test2",
                    Password = PasswordHasher.HashPassword("123456"),
                    Email = "wtlemon@126.com",
                    Mobile = "110",
                    Remark = "初始化测试账号"
                });
                await context.SaveChangesAsync();
            }
        }
        
        /// <summary>
        /// 注册Cors配置
        /// </summary>
        /// <param name="provider"></param>
        private static async Task RegisterCorsSettingsAsync(IServiceProvider provider)
        {
            var context = provider.GetRequiredService<ApplicationDbContext>();
            if (!context.CorsSettings.Any())
            {
                await context.CorsSettings.AddAsync(new Models.CorsSetting
                {
                    PolicyName = "AllowSpecificOrigins",
                    AllowedOrigins = "https://localhost:7164,https://localhost:7002",
                    AllowCredentials = true,
                    AllowAnyHeader = true,
                    AllowAnyMethod = true
                });
                await context.SaveChangesAsync();
            }
        }
    }
}
